/** ****************************************************************************
 * CopyRight (C) 2012 Sharadendu Sinha.
 * Licensing : FreeBSD 
 *
 * @(#) $Id$
 */
package com.sps.signalling;

import java.util.ArrayList;
import java.util.List;

import com.sps.signalling.exceptions.SignallingException;

/**
 * Provides partial implementation of {@link Invokable}. This is the base calss
 * for {@link Signal} and {@link Slot}
 * 
 * @version 1.1
 * @author sharadendu
 */
public abstract class AbstractInvokable
	implements Invokable
{
	/** name of the signal */
	private final String					name;
	/** the {@link InvokableProvider} for this {@link Invokable} */
	private final InvokableProvider			invokableProvider;
	/** {@link List} of all {@link InvokableConnection}s */
	private final List<InvokableConnection>	connections	= new ArrayList<InvokableConnection>();

	/**
	 * Only constructor used to initialize {@link #name} and
	 * {@link #invokableProvider}
	 * 
	 * @param name name of the {@link Invokable}
	 * @param invokableProvider {@link InvokableProvider} may be
	 *            {@link SignalEmmiter} or {@link SlotProvider}
	 * @throws SignallingException if name or {@link InvokableProvider} is null
	 */
	public AbstractInvokable(String name, InvokableProvider invokableProvider)
		throws SignallingException
	{
		if(name == null || name.length() == 0)
			throw new SignallingException(SignallingException.INVALID_NAME);
		if(invokableProvider == null)
			throw new SignallingException(
				SignallingException.INVOKABLE_PROVIDER_NULL);
		this.name = name;
		this.invokableProvider = invokableProvider;
		this.invokableProvider.addInvokable(this);
	}

	/**
	 * @see com.sps.signalling.Invokable#getName()
	 */
	@Override
	public String getName()
	{
		return name;
	}

	/**
	 * @see com.sps.signalling.Invokable#getProvider()
	 */
	@Override
	public InvokableProvider getProvider()
	{
		return invokableProvider;
	}

	/**
	 * @see com.sps.signalling.Invokable#addConnection(com.sps.signalling.InvokableConnection)
	 */
	@Override
	public void addConnection(InvokableConnection connection)
	{
		if(!connections.contains(connection))
		{
			connections.add(connection);
		}
	}

	/**
	 * @see com.sps.signalling.Invokable#removeConnection(com.sps.signalling.InvokableConnection)
	 */
	@Override
	public void removeConnection(InvokableConnection connection)
	{
		if(connections.contains(connection))
		{
			connections.remove(connection);
		}
	}

	/**
	 * @see com.sps.signalling.Invokable#resetConnections()
	 */
	@Override
	public void resetConnections()
	{
		connections.clear();
	}

	/**
	 * @see com.sps.signalling.Invokable#getConnections()
	 */
	@Override
	public List<InvokableConnection> getConnections()
	{
		return connections;
	}

	/**
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object obj)
	{
		boolean equals = false;
		if(obj instanceof Invokable)
		{
			Invokable invokable = (Invokable)obj;
			equals = invokable.getName().equals(name)
				&& invokable.getProvider().equals(invokableProvider);
		}
		return equals;
	}

	/**
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode()
	{
		return name.hashCode() | invokableProvider.hashCode();
	}

	/**
	 * @see com.sps.signalling.Invokable#getConnection(com.sps.signalling.Invokable,
	 *      com.sps.signalling.Invokable,
	 *      com.sps.signalling.InvokableConnection.Type)
	 */
	@Override
	public InvokableConnection getConnection(Invokable signal,
		Invokable invokable, com.sps.signalling.InvokableConnection.Type type)
	{
		InvokableConnection foundConnection = null;
		for(InvokableConnection connection : connections)
		{
			if(connection.getSourceInvokable().equals(signal)
				&& connection.getDestinationInvokable().equals(invokable)
				&& connection.getType() == type)
			{
				foundConnection = connection;
				break;
			}
		}
		return foundConnection;
	}
}
